using System;
using System.Linq;
using Boo.Lang.Compiler.Ast;

namespace Mite.DSL
{
	/// <summary>
	/// Before macros are expanded, transform specified MacroStatements with blocks 
	/// by promoting the BlockExpression to an argument to 
	/// the macro.
	/// <example>
	/// 
	/// DoSomething:
	///		x = 1 + 1
	///		return x
	/// 
	/// is transformed into 
	/// DoSomething(do():
	///		x = 1 + 1
	///		return x)
	///		
	/// </example>
	/// </summary>
	public class PromoteBlockExpressionToArgumentTransformer : DepthFirstTransformer
	{
		/// <summary>
		/// Creates an instance of PromoteBlockExpressionToArgumentTransformer.
		/// </summary>
		/// <param name="macros">Macros to transform.</param>
		/// <exception cref="ArgumentNullException"><paramref name="macros"/> can not be null.</exception>
		/// <exception cref="ArgumentException"><paramref name="macros"/> can not be empty.</exception>
		public PromoteBlockExpressionToArgumentTransformer(params string[] macros)
		{
			Guard.SequenceNotNullOrEmpty("macros", macros);
			this.macros = macros;
		}

		/// <summary>
		/// Handles <see cref="MacroStatement"/> nodes.
		/// </summary>
		/// <param name="node">The node to handle.</param>
		public override void OnMacroStatement(MacroStatement node)
		{
			if (macros.Contains(node.Name))
			{
				if (node.Block.HasStatements)
				{
					var blockExpression = new BlockExpression(node.Block.LexicalInfo, node.Block.CloneNode());
					node.Arguments.Add(blockExpression);
					node.Block.Clear();
				}
			}
			base.OnMacroStatement(node);
		}

		private readonly string[] macros;
	}
}